﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp.WinForms;
using CefSharp;
using CefSharp.WinForms.Internals;
using Chen.CefWebKit.Handler;
using Chen.CefWebKit.Tool;
using System.Threading;
using Chen.CefWebKit.Factory;

namespace Chen.CefWebKit.WebBrowser
{
    public partial class BrowserTabUserControl : UserControl
    {
        public IWinFormsWebBrowser Browser { get; private set; }
        RenderProcessMessageHandler RenderProcessMessage;
        public TextBoxFormat TextMessageBox { get; set; }
        /// <summary>
        /// Cookie管理员对象
        /// </summary>
        public ICookieManager cookieManager { get; set; }
        /// <summary>
        /// 根据Url监控Response工厂对象
        /// </summary>
        public ResponseUrlFilterFacotorys urlFilterFacotrys { get; set; }

        #region 一些设置
        /// <summary>
        /// 是否显示一些全局消息
        /// </summary>
        public bool UseGlobalMessage = false;
        #endregion

        public BrowserTabUserControl(string CookiePath="cookie",bool CanUserControll=false)
        {
            InitializeComponent();

            Dock = DockStyle.Fill;
            //var requestContextSettings = new RequestContextSettings { };
            var requestContext = new UserRequestContext(new RequestContextHandler(CookiePath));
            var browser = new ChromiumWebBrowser("")
            {
                Dock = DockStyle.Fill,
                RequestContext = requestContext,
                Enabled= CanUserControll,
            };
            browserPanel.Controls.Add(browser);//将浏览器页面加载到Panel中

            Browser = browser;
            cookieManager = requestContext.GetDefaultCookieManager(null);
            Browser.AddressChanged += OnBrowserAddressChanged;

            RenderProcessMessage = new RenderProcessMessageHandler();
            Browser.RenderProcessMessageHandler = RenderProcessMessage;

            urlFilterFacotrys = new ResponseUrlFilterFacotorys();
            Browser.RequestHandler = new RequestHandler(urlFilterFacotrys);

            TextMessageBox = new TextBoxFormat(browserTextBox);
        }

        #region Private
        private void BrowserTabUserControl_Load(object sender, EventArgs e)
        {
        }
        /// <summary>
        /// 当浏览器地址发生改变时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnBrowserAddressChanged(object sender, AddressChangedEventArgs args)
        {
            this.InvokeOnUiThreadIfRequired(() => urlLabel.Text = args.Address);
            if (UseGlobalMessage)
            {
                TextMessageBox.WriteLine($"页面[{args.Address}]加载成功！");
            }
        }
        #endregion

        #region 对象公共方法
        /// <summary>
        /// 获得Tab页面对象
        /// </summary>
        /// <returns></returns>
        public IWinFormsWebBrowser GetBrowser()
        {
            return Browser;
        }
        /// <summary>
        /// 浏览器打开页面
        /// </summary>
        /// <param name="url">链接</param>
        public void LoadUrl(string url)
        {
            Browser.Load(url);
            //Task t = LoadPageAsync(wb, url);
            //t.Wait();
        }
        /// <summary>
        /// 运行JS代码
        /// </summary>
        /// <param name="script">JS代码</param>
        /// <returns></returns>
        public string RunScript(string script)
        {
            if (RenderProcessMessage.CanScript)
            {
                Task<JavascriptResponse> Tjs = Browser.EvaluateScriptAsync(script);
                Tjs.Wait();
                if (Tjs.Result.Result != null)
                {
                    string a = Tjs.Result.Result.ToString();
                    return a;
                }
            }
            return null;
        }
        /// <summary>
        /// 获得当前标签页的URL
        /// </summary>
        /// <returns></returns>
        public string GetUrl()
        {
            return Browser.Address;
        }
        /// <summary>
        /// 获取所有Cookie
        /// </summary>
        /// <returns></returns>
        public List<Cookie> GetAllCookie()
        {
            //cookieManager.VisitAllCookies(cookieVisitor);
            var _cookies=cookieManager.VisitAllCookiesAsync();
            _cookies.Wait(5000);
            var cookies = _cookies.Result;
            return cookies;
            //string script = "document.cookie";
            //Task<JavascriptResponse> Tjs = Browser.EvaluateScriptAsync(script);
            //Tjs.Wait();
            //string Result = Tjs.Result.Result.ToString();
            //return Result;
        }
        /// <summary>
        /// 获得指定站点的Cookie，为空则获得当前页面站点Cookie
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public List<Cookie> GetUrlCookie(string url="")
        {
            if (string.IsNullOrEmpty(url))
            {
                string _url = GetUrl();
            }
            var _cookies = cookieManager.VisitUrlCookiesAsync(url, false);
            _cookies.Wait(5000);
            var cookies = _cookies.Result;
            return cookies;
        }
        /// <summary>
        /// 设置Cookie
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="value">对应值</param>
        /// <param name="domain">所在域名</param>
        public bool SetCookie(Cookie cookie,string url="/")
        {
            return cookieManager.SetCookie(url, cookie);
        }
        /// <summary>
        /// 设置多个Cookie
        /// </summary>
        /// <param name="cookies"></param>
        public void SetCookies(Cookie[] cookies,string url="/")
        {
            foreach (Cookie i in cookies)
            {
                SetCookie(i,url);
            }
        }
        /// <summary>
        /// 设置Cookie
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="path"></param>
        /// <param name="domain"></param>
        /// <returns></returns>
        public bool SetCookie(string name,string value,string path,string domain)
        {
            Cookie cookie = new Cookie() {
                Creation=DateTime.Now,
                Name=name,
                Value=value,
                Path=path,
                Domain=domain
            };
            return SetCookie(cookie);
        }
        /// <summary>
        /// 删除Cookie如果Url和Name都为空，则删除所有Cookie
        /// </summary>
        /// <param name="url"></param>
        /// <param name="name"></param>
        /// <param name="waitTime"></param>
        /// <returns></returns>
        public int DeleteCookie(string url=null,string name=null,int waitTime=3000)
        {
            Task<int> _t=cookieManager.DeleteCookiesAsync(url,name);
            if (_t.Wait(waitTime))
            {
                return _t.Result;
            }
            else
            {
                return -1;
            }
        }
        /// <summary>
        /// 通过Query语句获得Html代码
        /// </summary>
        /// <param name="Selector"></param>
        /// <returns></returns>
        public string GetHtmlByQuery(string Selector)
        {
            string Script = JavaScriptLibrary.QuerySelector(Selector);
            string result = RunScript(Script);
            return result;
        }
        /// <summary>
        /// 获得当前页面的HTML代码
        /// </summary>
        /// <returns></returns>
        public String GetHtml()
        {
            string Script = JavaScriptLibrary.QuerySelector("body");
            string result = RunScript(Script);
            return result;
            //Task<string> Thtml = wb.GetBrowser().MainFrame.GetSourceAsync();
            //Thtml.Wait();
            //HtmlCode = Thtml.Result;
            //return HtmlCode;
        }
        /// <summary>
        /// 访问一个连接，并等待渲染完成
        /// </summary>
        /// <param name="url">网址</param>
        /// <param name="querySelecot">判断渲染完成的Query选择器标签</param>
        /// <param name="Timeout">超时时间</param>
        /// <param name="maxRetry">最大重试次数</param>
        /// <returns>是否渲染完成</returns>
        public bool LoadAndWaitRender(string url, string querySelector, int Timeout = 5000, int maxRetry = 1, int tryCount = 0)
        {
            ClearWebPage(50);
            LoadUrl(url);
            int Retry = 0;
            bool isSuccess = false;
            while (!isSuccess && Retry < maxRetry)
            {
                isSuccess = WaitRenderOver(querySelector, new CancellationTokenSource(Timeout));
                if (!isSuccess)
                {
                    Retry++;
                    LoadUrl(url);
                }
            }
            return isSuccess;
        }
        /// <summary>
        /// 访问一个连接并等待一定时间
        /// </summary>
        /// <param name="url"></param>
        /// <param name="waitTime"></param>
        public void LoadAndWait(string url, int waitTime)
        {
            LoadUrl(url);
            Thread.Sleep(waitTime);
        }
        /// <summary>
        /// 释放页面连接（每次用完页面后请务必释放页面,以防止通过标签判断页面是否渲染失效）
        /// </summary>
        /// <param name="waitTime"></param>
        public void ClearWebPage(int waitTime)
        {
            LoadAndWait("about:blank", waitTime);
        }
        /// <summary>
        /// 判断指定标签对象 是否存在页面上
        /// </summary>
        /// <param name="querySelector">对象选择器</param>
        /// <returns></returns>
        public bool HasNode(string querySelector)
        {
            bool result = false;
            string _html = GetHtmlByQuery(querySelector);
            if (_html != null)
            {
                result = true;
            }
            return result;
        }
        /// <summary>
        /// 通过判断指定标签对象，等待页面渲染完成
        /// </summary>
        /// <param name="querySelector"></param>
        /// <returns></returns>
        public bool WaitRenderOver(string querySelector, CancellationTokenSource CancelToken)
        {
            bool result = false;
            while (!result && !CancelToken.IsCancellationRequested)
            {
                result = HasNode(querySelector);
                Thread.Sleep(500);
            }
            return result;
        }
        /// <summary>
        /// 不渲染获得页面数据
        /// </summary>
        /// <returns></returns>
        public string GetStringWithoutRenderer(string url,Encoding encode=null)
        {
            CookieUserVisitor cookiev = new CookieUserVisitor();
            cookieManager.VisitAllCookies(cookiev);
            AdvanceClient classClient = new AdvanceClient(cookiev.GetContainer());
            string result = classClient.GetString(url, encode);
            return result;
        }
        #endregion
    }
}
